# !/usr/bin/env python
#
# Copyright 2008 CPedia.com.
#
# New portions Copyright 2009, 2010 Rob Stenzinger 
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

__author__ = 'Ping Chen, Rob Stenzinger'

import cgi
import wsgiref.handlers
import os
import re
import datetime
import calendar
import logging
import string
import urllib

import simplejson

from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.api import memcache
from google.appengine.ext import search
from google.appengine.api import mail

import model
from model import Archive,Weblog,WeblogReactions,Book,Chapter,Tag
import authorized
import view
import util

"""
======================================================================
Config/Global settings that don't yet belong in a separate config file. 
======================================================================
"""
nav_context_list = [
"type",
"book",
"chapter",
"permalink",
"tag",
"search",
"list",
"format",            
"sort",            
"nav_mode", 
"page", 
"random", 
"jump", 
"fullscreen",
] 

appengine_edit_url = "<a href='http://appengine.google.com/datastore/edit?app_id=__application__&key=__key__'>edit</a>"

admin_list_config = {
            "lists":["Weblog","WeblogReactions","Book","Chapter","Tag"],
            "links":{"Weblog":["<a href='/edit/blog/__id__'>edit</a>","<a href='/delete/blog/__id__'>delete</a>"],
                     #"WeblogReactions":["<a href='/edit/comment/__id__'>edit</a>","<a href='/delete/comment/__id__'>delete</a>"],
                     "WeblogReactions":[appengine_edit_url],
                     "Book":[appengine_edit_url],
                     "Chapter":[appengine_edit_url],
                     "Tag":[appengine_edit_url],
            },
            "listFilters":{"Weblog":{"status":model.config_post_status_types, "entrytype":model.config_post_types, "title":"", "content":"", "date":""},
                           "WeblogReactions":{"status":model.config_response_status_types, "title":"", "content":"", "date":""},
                           "Book":{"title":"", "description":""},
                           "Chapter":{"title":"", "description":""},
                           "Tag":{"tag":""}
            },
            "action_urls":{"Weblog":[{"action":"Publish Scheduled", "url":"/admin/automation/publish"}],
                     "WeblogReactions":[],
                     "Book":[{"action":"Reset Entry Counters", "url":"/admin/book/resetentrycount"}],
                     "Chapter":[{"action":"Reset Entry Counters", "url":"/admin/chapter/resetentrycount"}],
                     "Tag":[{"action":"Reset Entry Counters", "url":"/admin/tag/resetentrycount"}],
            },            
        }
        
"""
======================================================================
Base class for all requests, establishes common navigation context, 
also offers a common way to generate output w/templates via "generate()"
======================================================================
"""        
        
class BaseRequestHandler(webapp.RequestHandler):
    """Supplies a common template generation function.
    """
    nav_context = {}
    config = None
    def generate(self, template_name, template_values={}, page_object_parameter_name=""):
        archiveList = util.archiveList()
        bookList = util.bookList()
        
        if self.config is None:
            self.config = util.get_config()

        values = {
          'archiveList': archiveList,
          'bookList': bookList,          
        }
        values.update(template_values)
        view.ViewPage(cache_time=0).render(self, template_name, values, self.config["template_theme_directory"], page_object_parameter_name)
        
    def nav_context_template(self):
        _nav_context = {}
        for item in nav_context_list:
            _nav_context[item] = ""
        return _nav_context
    
    def reset_nav_context(self):
        # clear the nav context
        self.nav_context = self.nav_context_template()
        
    def update_nav_context(self, alternateParameters=None):
        if alternateParameters is None:
            restParameters = self.request.path.split("/")
        else:
            restParameters = alternateParameters
        #.../type/blog/book/BOOKNAME/chapter/CHAPTERNAME/tag/TAG1/TAG2/search/WORD/version/VERSIONLABEL
        #todo:
        #nav_version_label
        
        #note: currently enforcing < 500 parameters as safety precaution
        if len(restParameters) <= 1 or len(restParameters) > 500:
          self.reset_nav_context()
        else:
            # if params are found, they're added to the context and automatically put to use based on certain API calls e.g.: /filter or /type
            
            #todo:
            # optional for other api rest handlers
            self.reset_nav_context()            

            currentItemValue = ""            
            currentResults = {}
            itemValueTestList = []
            for prop in nav_context_list: #self.nav_context:
                currentResults[prop] = []
                itemValueTestList.append("/" + prop + "/")
            
            for item in restParameters:
                itemValue = str(item).lower()
                itemValueOriginal = str(item)
                if len(itemValue) > 0:
                    itemValueTest = "/" + itemValue + "/"

                    #todo: how to manage this list, essentially they're all reserved names for params/url string
                    if itemValueTest in itemValueTestList: 
                        currentItemValue = itemValue
                        currentResults[currentItemValue] = []
                        
                        #boolean values... their presence = Y
                        if currentItemValue == "list":
                            currentResults[currentItemValue].append("Y")    
                        elif currentItemValue == "random":
                            currentResults[currentItemValue].append("Y")    
                        elif currentItemValue == "jump":
                            currentResults[currentItemValue].append("Y")    
                        elif currentItemValue == "fullscreen":
                            currentResults[currentItemValue].append("Y")    
                                                                            
                    elif currentItemValue != "":                        
                        currentResults[currentItemValue].append(itemValueOriginal) #(itemValue)
            """
            all parameters that allow flexible input need urllib.unquote
            """
            if len(currentResults["fullscreen"]) > 0:
                self.nav_context["fullscreen"] = True
                        
            if len(currentResults["permalink"]) > 0:
                self.nav_context["permalink"] = currentResults["permalink"][0]

            if len(currentResults["type"]) > 0:
                self.nav_context["type"] = currentResults["type"][0]
                
            if len(currentResults["page"]) > 0:
                self.nav_context["page"] = currentResults["page"][0]

            if len(currentResults["random"]) > 0:
                self.nav_context["random"] = True

            if len(currentResults["jump"]) > 0:
                self.nav_context["jump"] = True

            if len(currentResults["book"]) > 0:
                self.nav_context["book"] = urllib.unquote(currentResults["book"][0])
               
            if len(currentResults["chapter"]) > 0:
                self.nav_context["chapter"] = urllib.unquote(currentResults["chapter"][0])

            if len(currentResults["tag"]) > 0:
                if len(currentResults["tag"][0]) == 0:
                    self.nav_context["tag"].append(currentResults["tag"])
                else:
                    self.nav_context["tag"] = currentResults["tag"]                    
                
                for tag in self.nav_context["tag"]:
                    self.nav_context["tag"] = urllib.unquote(tag)                

            if len(currentResults["search"]) > 0:
                self.nav_context["search"] = urllib.unquote(currentResults["search"][0])
                
            if len(currentResults["list"]) > 0:
                self.nav_context["list"] = currentResults["list"][0]
                
            if len(currentResults["format"]) > 0:
                self.nav_context["format"] = currentResults["format"][0]
                
            if len(currentResults["sort"]) > 0:
                #clean the input
                sort_result = ""
                if str(currentResults["sort"][0]).lower().find("-date") > -1:
                    sort_result = "-date"                    
                elif str(currentResults["sort"][0]).lower().find("date") > -1:
                    sort_result = "date"
                    
                if len(sort_result) == 0 and str(currentResults["sort"][0]).lower().find("-title") > -1:
                    sort_result = "-title"                    
                elif len(sort_result) == 0 and str(currentResults["sort"][0]).lower().find("title") > -1:
                    sort_result = "title"

                if len(sort_result) == 0 and str(currentResults["sort"][0]).lower().find("-commentcount") > -1:
                    sort_result = "-commentcount"                    
                elif len(sort_result) == 0 and str(currentResults["sort"][0]).lower().find("commentcount") > -1:
                    sort_result = "commentcount"
                                        
                self.nav_context["sort"] = sort_result

            # determine the navigation mode: nav_mode:
            if len(self.nav_context["nav_mode"]) == 0 and len(self.nav_context["book"]) > 0 and len(self.nav_context["chapter"]) > 0:
                self.nav_context["nav_mode"] = "book-chapter"
            elif len(self.nav_context["nav_mode"]) == 0 and len(self.nav_context["book"]) > 0:
                self.nav_context["nav_mode"] = "book"
            elif len(self.nav_context["nav_mode"]) == 0 and len(self.nav_context["chapter"]) > 0:
                self.nav_context["nav_mode"] = "chapter"
            elif len(self.nav_context["nav_mode"]) == 0 and len(self.nav_context["tag"]) > 0:
                self.nav_context["nav_mode"] = "tag"
            elif len(self.nav_context["nav_mode"]) == 0 and len(self.nav_context["type"]) > 0:
                self.nav_context["nav_mode"] = "type"
            elif len(self.nav_context["nav_mode"]) == 0 and len(self.nav_context["search"]) > 0:
                self.nav_context["nav_mode"] = "search"
            else:
                self.nav_context["nav_mode"] = "timeline"        
                    
"""
======================================================================
Blog URL Handlers, from Not Found to Home/Main to RSS/Atom, etc...
======================================================================
"""        
      
class NotFoundHandler(webapp.RequestHandler):
    def get(self):
        self.error(404)
        view.ViewPage(cache_time=36000).render(self)


class UnauthorizedHandler(webapp.RequestHandler):
    def get(self):
        self.error(403)
        view.ViewPage(cache_time=36000).render(self)
        
        
class MainPage(BaseRequestHandler):
  def get(self):
    if self.config is None:
        self.config = util.get_config()    
      
    pageStr = self.request.get('page')
    if pageStr:
        page = int(pageStr)
    else:
        page = 1;
        
    blogs_result = None
            
    try:
        # blog posts for main page
        nav_context_alternate = self.nav_context_template()
        nav_context_alternate["type"] = "post"    
        nav_context_alternate["sort"] = "-date"    
        blogs_result = util.get_blogs(self, page, nav_context_alternate, self.config["main_page_post_list_limit"])  
    except:
        pass
    
    if blogs_result is not None:        
        # featured post
        nav_context_featured = self.nav_context_template()
        nav_context_featured["type"] = self.config["featured_post_type"]
        nav_context_featured["jump"] = True
        nav_context_featured["sort"] = "-date"    
        featured_post = util.get_blogs(self, page, nav_context_featured)["single"]
        if featured_post is not None:
            featured_post.document = simplejson.loads(featured_post.json_document)
            nav_context_featured["book"] = featured_post.book
            nav_context_featured["chapter"] = featured_post.chapter
            nav_context_featured["mode"] = "type"
            #nav_context_featured["book"] = None
            #nav_context_featured["chapter"] = None
            self.nav_context = nav_context_featured
            #self.nav_context = self.nav_context_template()
    
        recentReactions = util.getRecentReactions()
            
        final_blogs_result = None
        total_pages = None
        next_page = None
        previous_page = None
        entrytype = None
        
        try:
            if blogs_result:
        
                if blogs_result["list"]:
                    # render as a list results page
                    recentReactions = util.getRecentReactions()
                    total_pages = int(round(blogs_result["total_pages"],0))
                    if page + 1 < total_pages:
                        next_page = page + 1
                    if page - 1 > 1:
                        previous_page = page - 1
                               
                    for blog in blogs_result["list"]["object_list"]:
                        #util.getLogger(__name__).debug(str(blog))  
                        entrytype = blog.entrytype
                        if blog.content:
                            blog.document = simplejson.loads(blog.json_document)
                
                    final_blogs_result = blogs_result["list"]
        except:
            # no records... 
            pass
        
        template_values = {
          'page':final_blogs_result,
          'entrytype':entrytype,
          'featured':featured_post,
          'recentReactions':recentReactions,
          'current_page':page,
          'previous_page':previous_page,
          'next_page':next_page,
          'total_pages':total_pages,
          }
        self.generate('home.html', template_values, "featured")
    else:
        self.generate('home.html', None)

class BlogPageHandle(BaseRequestHandler):
  def get(self,pagenum):
    page = int(pagenum)

    if self.config is None:
        self.config = util.get_config()    

    # blog posts for main page
    blog = None
    try:
        blog = util.get_blogs(self, page)    
    except:
        pass
    
    if blog is None:
        self.redirect('/')
    else:
        recentReactions = util.getRecentReactions()        

        blog.document = simplejson.loads(blog.json_document)        
        template_values = {
          'page':blog,
          'recentReactions':recentReactions,
          }
        self.generate('blog_main.html', template_values, "page")

# BlogFilterHandle
# behaves as a general navigation and filter api for the blog
class BlogFilterHandle(BaseRequestHandler):
  def get(self,pagenum=1):
      
    if self.config is None:
        self.config = util.get_config()    
      
    page = int(pagenum)
    self.update_nav_context()
    
    if self.nav_context["page"] and int(self.nav_context["page"]) > 0:
        page = int(self.nav_context["page"])
    
    blogs_result = util.get_blogs(self, page, None, 2)

    entrytype = None
    next_page = None
    previous_page = None
    
    if blogs_result:

        if blogs_result["list"]:
            # render as a list results page
            recentReactions = util.getRecentReactions()
            
            for blog in blogs_result["list"]["object_list"]:
                #util.getLogger(__name__).debug(str(blog))  
                entrytype = blog.entrytype
                if blog.content:
                    blog.document = simplejson.loads(blog.json_document)

            total_pages = int(round(blogs_result["total_pages"],0))
            
            if page + 1 < total_pages:
                next_page = page + 1
            if page - 1 > 1:
                previous_page = page - 1
                
            template_values = {
              'page':blogs_result["list"],
              'recentReactions':recentReactions,
              'entrytype':entrytype,
              'current_page':page,
              'previous_page':previous_page,
              'next_page':next_page,
              'total_pages':total_pages,
              'results_per_page':blogs_result["results_per_page"],
            }
            
            self.generate('blog_main.html', template_values, "list")
            
        elif blogs_result["single"]:
            # render as a single page

            reactions = util.get_blog_reactions(blogs_result["single"])                            
            recentReactions = util.getRecentReactions()            

            blogs_result["single"].document = simplejson.loads(blogs_result["single"].json_document)            
            
            template_values = {
              'recentReactions':recentReactions,
              'blog': blogs_result["single"],
              'reactions': reactions,
              }
            self.generate('blog_view.html', template_values, "blog")
                                
        else:
            blogs_result = None
    
    if not blogs_result:
       self.redirect('/')


class ArchiveHandler(BaseRequestHandler):
    def get(self, monthyear):
        if self.config is None:
            self.config = util.get_config()    
        
        #get blogs in month from cache.        
        blogs = util.getArchiveBlog(monthyear)

        recentReactions = util.getRecentReactions()
        for blog in blogs:
            #util.getLogger(__name__).debug(blog.json_document)
            try:
                blog.document = simplejson.loads(blog.json_document)            
            except:
                blog.document = ""
        page = {
            'object_list':blogs
        }
        template_values = {
          'monthyear':re.sub("-", " ", monthyear),
          'page':page,
          'recentReactions':recentReactions,
          }
        self.generate('blog_main.html', template_values, "list")


class ArticleHandler(BaseRequestHandler):
    def get(self,year,month, perm_stem):
        if self.config is None:
            self.config = util.get_config()    
        
        blogs = Weblog.all()
        blogs.filter("status =", model.config_post_status_default_ready)
        blogs.filter('permalink =',perm_stem)
        blog = blogs.get()
        if(blog is None):
            self.redirect('/')
            
        self.update_nav_context()            
        reactions = util.get_blog_reactions(blog)

        #todo
        try:
            blog.document = simplejson.loads(blog.json_document)            
        except:
            pass
        
        template_values = {
          'blog': blog,
          'reactions': reactions,
          }
        
        self.generate('blog_view.html', template_values, "blog")


class ArticleFullDateHandler(BaseRequestHandler):
    def get(self,year,month,day=None,perm_stem=None):            
        if self.config is None:
            self.config = util.get_config()    
        
        blog = None    
        if perm_stem:
            #blog = db.Query(Weblog).filter('permalink =',perm_stem).get()
            blogs = Weblog.all()
            blogs.filter("status =", model.config_post_status_default_ready)
            blogs.filter('permalink =',perm_stem)
            blog = blogs.get()
                        
        #todo: simplify this redundant code, make the mont lookup more flexible (month name, month number)
        if blog is None:
            monthyear = str(month) + "-" + str(year)
            #get blogs in month from cache.        
            blogs = util.getArchiveBlogNumericMonth(month, year)
    
            recentReactions = util.getRecentReactions()
            for blog in blogs:
                #util.getLogger(__name__).debug(blog.json_document)
                try:
                    blog.document = simplejson.loads(blog.json_document)            
                except:
                    blog.document = ""
            page = {
                'object_list':blogs
            }
            template_values = {
              'monthyear':re.sub("-", " ", monthyear),
              'page':page,
              'recentReactions':recentReactions,
              }
            self.generate('blog_main.html', template_values, "list")            
            
            if blogs is None:
                self.redirect('/')
        else:    
            self.update_nav_context()            
            reactions = util.get_blog_reactions(blog)
    
            #todo
            try:
                blog.document = simplejson.loads(blog.json_document)            
            except:
                pass
            
            template_values = {
              'blog': blog,
              'reactions': reactions,
              }
            
            self.generate('blog_view.html', template_values, "blog")

class PageHandler(BaseRequestHandler):
    def get(self,perm_stem):
        blogs = Weblog.all()
        blogs.filter("status =", model.config_post_status_default_ready)
        blogs.filter('permalink =',perm_stem)
        blog = blogs.get()
 
        if self.config is None:
            self.config = util.get_config()    
               
        if not blog:
            self.redirect('/')
            
        self.update_nav_context()
        reactions = util.get_blog_reactions(blog) 
        test = {}

        try:
            if blog and blog.content:
                blog.document = simplejson.loads(blog.json_document)            
        except:
            #todo: log error
            self.redirect('/')
        
        template_values = {
          'blog': blog,
          'reactions': reactions,
          }
        self.generate('blog_view.html', template_values, "blog")


class SiteMapHandler(BaseRequestHandler):
    def get(self):
        blogs = Weblog.all()
        blogs.filter("status =", model.config_post_status_default_ready)
        blogs.order('-date')
        
        if self.config is None:
            self.config = util.get_config()    
                
        template_values = {
          'allblogs': blogs.fetch(1000),
          }
        self.generate('site_map.html', template_values, "none")


class FeedHandler(BaseRequestHandler):
    def get(self,tags=None):
        if self.config is None:
            self.config = util.get_config()
    
        self.update_nav_context()
        blogs_result = util.get_blogs(self, 1)
        last_updated = None
        blogs = None
        
        if blogs_result:
            blogs = []
            if blogs_result["list"]:
                # render as a list results page
                for blog in blogs_result["list"]["object_list"]:
                    #util.getLogger(__name__).debug(str(blog))  
                    if blog.content:
                        blog.json_document = re.sub(r'''src=\\"/(\S)''', r'src=\"' + self.config['root_url'] + r'\1', blog.json_document)
                        blog.json_document = re.sub(r"""src='/(\S)""", r"src='" + self.config["root_url"] + r"\1", blog.json_document)
                        blog.document = simplejson.loads(blog.json_document)    

                    blog.formatted_date = blog.date.strftime("%Y-%m-%dT%H:%M:%SZ")
                                        
                blogs = blogs_result["list"]["object_list"]
                                
            elif blogs_result["single"]:
                # render as a single page
    
                reactions = util.get_blog_reactions(blogs_result["single"])                            
                #recentReactions = util.getRecentReactions()           
                blogs_result["single"].document = simplejson.loads(blogs_result["single"].json_document)            

                blogs.append(blogs_result["single"])

            if blogs and blogs[0]:
                last_updated = blogs[0].date
                last_updated = last_updated.strftime("%Y-%m-%dT%H:%M:%SZ")
                
            page = {
                    'object_list':blogs
            } 
            self.generate('atom.xml',{'page':page,'last_updated':last_updated}, "list")
    

class ThemeAssetHandler(BaseRequestHandler):
    def get(self, filename):
        self.fetch_asset(filename)   
    def fetch_asset(self, filename):
        util.getLogger(__name__).debug("Theme asset name: %s" % filename)            
        dirname = os.path.dirname(__file__)
        
        if self.config is None:
            self.config = util.get_config()
                    
        template_folder = self.config["template_theme_directory"] + "/assets/"       
        extension = str(os.path.splitext(filename)[-1]).lower()
        content_header = ""
        template_file = None
        
        if str(filename).lower().find("admin") > 0:
            template_file = os.path.join(dirname, os.path.join('templates', filename))
        elif template_folder != "":
            try:
                template_file = os.path.join(dirname, os.path.join(os.path.join('templates', template_folder), filename))
            except:
                pass

        if template_file is None:
            template_file = os.path.join(dirname, os.path.join('templates', filename))
                    
        util.getLogger(__name__).debug("Using Theme asset at %s", template_file)
        output = open(template_file).read()
        
        if extension in ["png", "gif", "jpg", "jpeg"]:
            content_header = "image/" + extension
        elif extension == "ico":            
            content_header = "text/plain"
        elif extension == "html":
            content_header = "text/html"
        else:
            content_header = "text/plain"
        
        self.response.clear()
        self.response.headers["Content-Type"] = content_header
        self.response.out.write(output)        


class ThemeAssetHandlerFavIco(ThemeAssetHandler):
    def get(self):
        self.fetch_asset("favicon.ico")   
        
        
class ThemeAssetHandlerFavPNG(ThemeAssetHandler):
    def get(self):
        self.fetch_asset("favicon.png")           


"""
======================================================================
Administrative URL Handlers, all except AddBlogReaction, Login, and Logout
 require an admin login.
======================================================================
"""     

class Admin(BaseRequestHandler):
    @authorized.role("admin")
    def get(self):  
        template_values = {
          }
        self.generate('admin.html', template_values, "admin")
   
class Login(BaseRequestHandler):
    def get(self, error_msg=None):
        #self.redirect(users.create_login_url(self.request.uri))
        self.redirect(users.create_login_url("/"))
        
                
class Logout(BaseRequestHandler):
    def get(self, error_msg=None):
        if users.get_current_user():
            self.redirect(users.create_logout_url(self.request.uri))
            return
        self.redirect("/")  

        
class AddBlog(BaseRequestHandler):
  @authorized.role("admin")
  def get(self,entrytype):
    template_values = {
      'entrytype': entrytype,
      'action': "addBlog",
      }
    self.generate('blog_add.html', template_values, "admin")

  @authorized.role("admin")
  def post(self,entrytype):
    user = users.get_current_user()
    blog = Weblog()
    blog.title = self.request.get('title_input')
    blog.content = self.request.get('text_input')
    
    if self.request.get('status'):
        blog.status = self.request.get('status') 

    if self.request.get('date'):
        blog.date = model.parseDate(self.request.get('date'))    

    if self.request.get('entrytype'):
        entrytype = self.request.get('entrytype')
    
    if entrytype not in model.config_post_types:
        entrytype =  model.config_post_default
    
    blog.chapter = self.request.get('chapter')
    blog.book = self.request.get('book')
    blog.author = user
    blog.authorEmail = user.email()

    tags = self.request.get('tags')
    blog.tags_commas = tags
        
    blog.entrytype = entrytype
    template_values = {
      'entrytype': entrytype,
      'blog': blog,
      'action': "addBlog",
      'tags': tags,
      }
  
    blog.permalink = get_permalink(blog.title)
    blog.save()
    util.flushBlogMonthCache(blog)
    util.flushBlogPagesCache()
    util.flushTagList()
    self.redirect('/'+blog.relative_permalink())    


def get_permalink(title):
    permalink = ""
    try:
        permalink = util.slugify(title)
        if not permalink:
            raise Exception
    except Exception,e:
        print e
        #throw('Generate permanent link for blog error, please retry it.')
        #return

    
    blogs = Weblog.all()
    blogs.filter('permalink',permalink)
    total = blogs.count()
    
    if total > 0:
        permalink = permalink + str(total+1)
        
    return permalink


class EditBlog(BaseRequestHandler):
    @authorized.role("admin")
    def get(self,entrytype,blogId):
        blog = Weblog.get_by_id(int(blogId))
        template_values = {
        'blog': blog,
        'action': "editBlog",
        }
        self.generate('blog_add.html', template_values, "admin")

    @authorized.role("admin")
    def post(self,entrytype,blogId):
        blog = Weblog.get_by_id(int(blogId))
        if(blog is None):
            self.redirect('/')

        #if blog.entrytype == 'page':
        if self.request.get('permalink'):
            blog.permalink = self.request.get('permalink') 

        if self.request.get('entrytype'):
            blog.entrytype = self.request.get('entrytype') 

        if self.request.get('status'):
            blog.status = self.request.get('status') 

        if self.request.get('date'):
            blog.date = model.parseDate(self.request.get('date'))
            
        blog.title = self.request.get('title_input')
        blog.content = self.request.get('text_input')
        blog.chapter = self.request.get('chapter')
        blog.book = self.request.get('book')        
        blog.tags_commas = self.request.get('tags')
        user = users.get_current_user()
        blog.lastModifiedDate = datetime.datetime.now()
        blog.lastModifiedBy = user
        blog.update()
        util.flushBlogMonthCache(blog)
        util.flushBlogPagesCache()
        self.redirect('/'+blog.relative_permalink())


class DeleteBlog(BaseRequestHandler):
  @authorized.role("admin")
  def get(self,entrytype,blogId):
      blog = Weblog.get_by_id(int(blogId))
      template_values = {
      'blog': blog,
      'action': "deleteBlog",
      }
      self.generate('blog_delete.html', template_values, "admin")

  @authorized.role("admin")
  def post(self,entrytype,blogId):
    blog= Weblog.get_by_id(int(blogId))
    if(blog is not None):
        blogReactions = blog.weblogreactions_set
        for reaction in blogReactions:
            reaction.delete()
        blog.delete()
        util.flushBlogMonthCache(blog)
        util.flushBlogPagesCache()
    self.redirect('/')


class AddBlogReaction(BaseRequestHandler):
  def post(self):

    if self.config is None:
        self.config = util.get_config()
      
    blogId_ = self.request.get('blogId')
    blog= Weblog.get_by_id(int(blogId_))
    if(blog is None):
      self.redirect('/')
    blogReaction = WeblogReactions()
    blogReaction.weblog = blog
    blogReaction.content = self.request.get('text_input')
    if self.request.get('reply_to'):
        reply_to_key = self.request.get('reply_to')    
        blogReaction.reply_to = WeblogReactions.get_by_id(int(reply_to_key))
    
    blogReaction.authorWebsite = self.request.get('website')
    blogReaction.authorEmail = self.request.get('mail')
    blogReaction.user = self.request.get('name_input')
    clientIp = self.request.remote_addr
    
    if not util.akismet_validate_comment_ham(blogReaction.content, clientIp, blogReaction.authorWebsite, blogReaction.authorEmail, blogReaction.user):
        self.redirect('/')       
        return
    else:
        user = users.get_current_user()
        if user is not None:
            blogReaction.author = user
            blogReaction.authorEmail = str(user.email())
            blogReaction.user = str(user.nickname())
            blogReaction.status = "approved"
        blogReaction.userIp = clientIp
        save_result = blogReaction.save()
        util.flushRecentReactions()

        if save_result == True:
            post_url = "http://appengine.google.com/datastore/edit?app_id=" + self.config["application"] + "&key=" + str(blogReaction.key())
            admin_email_body = self.config["mail_new_comment_body"]
            admin_email_body = admin_email_body.replace("__post_url__", post_url)
            admin_email_body = admin_email_body.replace("__post_title__", blogReaction.weblog.title)
            mail.send_mail_to_admins(self.config["mail_new_comment_from_email"], self.config["application"], admin_email_body)
        
        if blogReaction.is_saved():
            self.redirect('/'+ blog.permalink + '#comment-' + str(blogReaction.key().id()))
        else:
            self.redirect('/'+ blog.permalink)
  

class EditBlogReaction(BaseRequestHandler):
    @authorized.role("user")
    def get(self,reactionId):
        blogReaction = WeblogReactions.get_by_id(int(reactionId))
        template_values = {
        'blogReaction': blogReaction,
        'action': "editBlogReaction",
        }
        self.generate('blog_add.html', template_values, "user")

    @authorized.role("user")
    def post(self,reactionId):
        blogReaction= WeblogReactions.get_by_id(int(reactionId))
        
        if(blogReaction is None):
            self.redirect('/')
            
        blogReaction.content = self.request.get('text_input')
        
        blogReaction.authorWebsite = self.request.get('website')
        user = users.get_current_user()
        if user is not None:
            blogReaction.lastModifiedBy = user
            blogReaction.authorEmail = str(user.email())
            blogReaction.user = str(user.nickname())
        else:
            blogReaction.authorEmail = self.request.get('mail')
            blogReaction.user = self.request.get('name_input')
        blogReaction.lastModifiedDate = datetime.datetime.now()

        if not util.akismet_validate_comment_ham(blogReaction.content, clientIp, blogReaction.authorWebsite, blogReaction.authorEmail, blogReaction.user):
            self.redirect('/')
        
        blogReaction.put()
        self.redirect('/'+blogReaction.weblog.relative_permalink())
           

class DeleteBlogReaction(BaseRequestHandler):
  @authorized.role("admin")
  def get(self,reactionId):
      blogReaction = WeblogReactions.get_by_id(int(reactionId))
      template_values = {
      'reaction': blogReaction,
      'action': "deleteBlogReaction",
      }
      self.generate('blog_delete.html', template_values, "admin")

  @authorized.role("admin")
  def post(self,reactionId):
    blogReaction= WeblogReactions.get_by_id(int(reactionId))
    if(blogReaction is not None):
        blogReaction.delete()
        util.flushRecentReactions()
    self.redirect('/'+blogReaction.weblog.relative_permalink())


"""
======================================================================
Administrative URL JSON/REST style Handlers
======================================================================
"""   
class AdminTagResetCount(BaseRequestHandler):
    @authorized.role("admin")
    def get(self):
        if self.config is None:
            self.config = util.get_config()

        result_object = {}        
        totals = util.entrycount_reset_tags() 
        result_object["totals"] = totals
        if totals is not None:
            result_object["status"] = "success"
        else:
            result_object["status"] = "error"
             
        self.response.clear()
        self.response.headers["Content-Type"] = "text/plain"
        self.response.out.write(simplejson.dumps(result_object))         


class AdminBookResetCount(BaseRequestHandler):
    @authorized.role("admin")
    def get(self):
        if self.config is None:
            self.config = util.get_config()

        result_object = {}        
        totals = util.entrycount_reset_books() 
        result_object["totals"] = totals
        if totals is not None:
            result_object["status"] = "success"
        else:
            result_object["status"] = "error"

        self.response.clear()
        self.response.headers["Content-Type"] = "text/plain"
        self.response.out.write(simplejson.dumps(result_object))         


class AdminChapterResetCount(BaseRequestHandler):
    @authorized.role("admin")
    def get(self):
        if self.config is None:
            self.config = util.get_config()

        result_object = {}        
        totals = util.entrycount_reset_chapters() 
        result_object["totals"] = totals
        if totals is not None:
            result_object["status"] = "success"
        else:
            result_object["status"] = "error"

        self.response.clear()
        self.response.headers["Content-Type"] = "text/plain"
        self.response.out.write(simplejson.dumps(result_object))         


class AdminList(BaseRequestHandler):
    @authorized.role("admin")
    def get(self):
        if self.config is None:
            self.config = util.get_config()

        result_object = admin_list_config        

        for item in result_object["links"]:
            updated_links = []
            for link in result_object["links"][item]:
                link = link.replace("__application__",self.config["application"])                
                updated_links.append(link)
            result_object["links"][item] = updated_links

        model.json_lightweight = True
        self.response.clear()
        self.response.headers["Content-Type"] = "text/plain"
        self.response.out.write(simplejson.dumps(result_object, default = model.to_json))   
        

class AdminListFilter(BaseRequestHandler):
    @authorized.role("admin")
    def get(self,filter):

        lists = admin_list_config["lists"]
        listFilters = admin_list_config["listFilters"]
        
        options = filter.split("/")
        
        if options[0] in lists:    
            records = []
            names = []
            attributes = []    
            result_object = {"records":[],"names":[], "attributes":[]}
            
            if options[0] == "Weblog":
                search = Weblog.all()                
                names = ["Title", "Date", "Status", "Entry Type"]#,"Key","ID"]
                attributes = ["title","date","status", "entrytype"]#,"key","id"]
            elif options[0] == "WeblogReactions":
                search = WeblogReactions.all()                
                names = ["Content", "Date", "Status"]#,"Key","ID"]
                attributes = ["content","date","status"]#,"key","id"]
            elif options[0] == "Book":
                search = Book.all()                
                names = ["Title","Description"]#,"Key","ID"]
                attributes = ["title","description"]#,"key","id"]
            elif options[0] == "Chapter":
                search = Chapter.all()                
                names = ["Title","Description"]#,"Key","ID"]
                attributes = ["title","description"]#,"key","id"]
            elif options[0] == "Tag":
                search = Tag.all()                
                names = ["Tag"]#,"Key","ID"]
                attributes = ["tag"]#,"key","id"]

            currentItemName = ""
            for item in options:
                try:
                    try:
                        if listFilters[options[0]][item] is not None:
                            currentItemName = item
                            continue
                    except:
                        pass

                    if currentItemName is not None:
                        if item is not None and len(item) > 0:
                            if currentItemName == "date":
                                item = model.parseDate(item)
                            search.filter(currentItemName + " = ", item)
                        currentItemName = None
                except:
                    pass

            results = search.fetch(1000)
            
            for item in results:
                result = {}
                for a in attributes:
                    #if a == "key":
                    #    result[a] = str(item.key())
                    #elif a == "id":
                    #    result[a] = str(item.key().id())
                    #else:
                    result[a] = eval("item." + a)
                    result["key"] = str(item.key())
                    result["id"] = str(item.key().id())
                records.append(result)
            
            result_object = {"records":records,"names":names, "attributes":attributes}
            model.json_lightweight = True
            self.response.clear()
            self.response.headers["Content-Type"] = "text/plain"
            self.response.out.write(simplejson.dumps(result_object, default = model.to_json))                    
